package com.yungu.swift.order.utils;


import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.constants.CommonConstant;
import com.yungu.swift.order.model.vo.PayVo;
import com.yungu.swift.utils.*;
import org.apache.commons.collections4.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import static com.yungu.swift.order.config.NacosListener.*;

/**
 * Description
 * <p>
 *
 * @author Zerrion
 * @author cuixiuyin
 * @date 2017/4/24
 */
@Component
public class PayDataBuilder {
    private static final Logger logger = LoggerFactory.getLogger(PayDataBuilder.class);

    //微信
    public static ResponseData<Map<String, String>> buildTenPayData(PayVo payVo) {

        String appid = "";
        String secret = "";
        String partner = "";
        String key = "";
        String openId = "";

        if (payVo.getPaySide() == CommonConstant.PASSENGER) {
            appid = WXPAY_CONFIG.getPassengerWxAppid();
            secret = WXPAY_CONFIG.getPassengerWxAppSecret();
            partner = WXPAY_CONFIG.getPassengerWxPartner();
            key = WXPAY_CONFIG.getPassengerWxAppKey();
        }
        if (payVo.getPaySide() == CommonConstant.PASSENGER_PULBIC) {
            appid = WXPAY_CONFIG.getPassengerPublicWxAppid();
            secret = WXPAY_CONFIG.getPassengerPublicWxAppSecret();
            partner = WXPAY_CONFIG.getPassengerPublicWxPartner();
            key = WXPAY_CONFIG.getPassengerPublicWxAppKey();
            openId = payVo.getOpenid();
        }
        if (payVo.getPaySide() == CommonConstant.PASSENGER_H5) {
            appid = WXPAY_CONFIG.getPassengerH5WxAppid();
            secret = WXPAY_CONFIG.getPassengerH5WxAppSecret();
            partner = WXPAY_CONFIG.getPassengerH5WxPartner();
            key = WXPAY_CONFIG.getPassengerH5WxAppKey();
        }
        if (payVo.getPaySide() == CommonConstant.PASSENGER_APPLET) {
            appid = WXPAY_CONFIG.getPassengerAppletWxAppid();
            secret = WXPAY_CONFIG.getPassengerAppletWxAppSecret();
            partner = WXPAY_CONFIG.getPassengerAppletWxPartner();
            key = WXPAY_CONFIG.getPassengerAppletWxAppKey();
            openId = payVo.getOpenid();
        }
        if (payVo.getPaySide() == CommonConstant.DRIVER) {
            appid = WXPAY_CONFIG.getDriverWxAppid();
            secret = WXPAY_CONFIG.getDriverWxAppSecret();
            partner = WXPAY_CONFIG.getDriverWxPartner();
            key = WXPAY_CONFIG.getDriverWxAppKey();
        }
        if (StringUtils.isEmpty(appid) || StringUtils.isEmpty(partner)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到微信配置参数");
        }

        Map<String, String> map = new HashMap<>(16);
        String totalFeeCent = payVo.getActualFare().multiply(new BigDecimal(100)).setScale(0,
                BigDecimal.ROUND_HALF_UP).toString();
        if ("0".equals(totalFeeCent)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "微信支付金额为0");
        }
        //微信回调地址
        String wxCallBackUrl = SYS_CONFIG.getWxPayCallback();
        //--以下为必填参数
        //公众账号ID
        map.put("appid", appid);
        //商户号
        map.put("mch_id", partner);
        //随机字符串
        map.put("nonce_str", Md5Utils.encode(String.valueOf(new Random().nextInt(10000))));
        //商品描述
        map.put("body", buildBody(payVo));
        //商户订单号
        map.put("out_trade_no", payVo.getTradeNo());
        //标价金额(以分为单位)
        map.put("total_fee", totalFeeCent);
        //终端IP
        map.put("spbill_create_ip", payVo.getSpbillCreateIp());
        //回调地址
        map.put("notify_url", wxCallBackUrl);
        //交易类型
        if (payVo.getPaySide() == CommonConstant.PASSENGER_PULBIC || payVo.getPaySide() == CommonConstant.PASSENGER_APPLET) {
            //微信公众号-小程序支付为"JSAPI"
            map.put("trade_type", "JSAPI");
            map.put("openid", openId);
        } else if (payVo.getPaySide() == CommonConstant.PASSENGER_H5) {
            //微信H5支付type 为"MWEB"
            map.put("trade_type", "MWEB");
        } else {
            map.put("trade_type", "APP");
        }
        System.out.println("支付参数：" + map);
        //签名
        String sign = PaySignBuilder.wxSignMD5(map, key);
        if (StringUtils.isEmpty(sign)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "参数MD5签名失败");
        }
        logger.info("微信支付请求加密串：" + sign);
        map.put("sign", sign);
        String payXml = XmlUtils.buildXml(map);
        logger.info("微信支付请求参数：" + payXml);

        //微信需要http通讯请求预支付信息
        TenpayHttpClient httpClient = new TenpayHttpClient();
        Map<String, String> resultMap = new HashMap<>();
        if (httpClient.callHttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder", payXml)) {
            String resultStr = httpClient.getResContent();
            resultMap = XmlUtils.readValueAsMap(resultStr);
        }
        if (resultMap == null || resultMap.isEmpty()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "微信XML解析异常");
        }
        if (!"SUCCESS".equals(resultMap.get("return_code"))) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "微信预支付通讯异常 -- " + resultMap.get("return_msg"));
        }
        if (!"SUCCESS".equals(resultMap.get("result_code"))) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "微信创建预支付异常 -- " + resultMap.get("err_code_des"));
        }

        Map<String, String> returnMap = new HashMap<>();
        //拼接返回值
        returnMap.put("appid", appid);
        returnMap.put("partnerid", partner);
        returnMap.put("prepayid", resultMap.get("prepay_id"));
        returnMap.put("package", "Sign=WXPay");
        returnMap.put("noncestr", Md5Utils.encode(String.valueOf(new Random().nextInt(10000))));
        returnMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        // 签名
        returnMap.put("sign", PaySignBuilder.wxSignMD5(returnMap, key));
        //前端容错多发送一个字段
        returnMap.put("pkg", "Sign=WXPay");

        if (payVo.getPaySide() == CommonConstant.PASSENGER_PULBIC || payVo.getPaySide() == CommonConstant.PASSENGER_APPLET) {
            //以下为微信h5支付的返回值
            Map<String, String> returnWxMap = new HashMap<>(16);
            //公众号名称，由商户传入
            returnWxMap.put("appId", appid);
            //时间戳，自1970年以来的秒数
            returnWxMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            //随机串
            returnWxMap.put("nonceStr", Md5Utils.encode(String.valueOf(new Random().nextInt(10000))));
            returnWxMap.put("package", "prepay_id=" + resultMap.get("prepay_id"));
            //微信签名方式
            returnWxMap.put("signType", "MD5");
            //微信签名
            returnWxMap.put("paySign", PaySignBuilder.wxSignMD5(returnWxMap, key));
            return ResponseData.buildSuccessResponse("微信生成预支付信息成功", returnWxMap);
        }
        if (payVo.getPaySide() == CommonConstant.PASSENGER_H5) {
            Map<String, String> returnWxMap = new HashMap<>(4);
            returnWxMap.put("mwebUrl", resultMap.get("mweb_url"));
            //微信H5支付返回中转链接地址
            return ResponseData.buildSuccessResponse("微信生成H5预支付信息成功", returnWxMap);
        }
        return ResponseData.buildSuccessResponse("微信生成预支付信息成功", returnMap);
    }

    //微信订单的查询
    public static ResponseData<Map<String, String>> selTenPayData(PayVo payVo) {
        String appid = "";
        String partner = "";
        String key = "";

        if (payVo.getPaySide() == CommonConstant.PASSENGER) {
            appid = WXPAY_CONFIG.getPassengerWxAppid();
            partner = WXPAY_CONFIG.getPassengerWxPartner();
            key = WXPAY_CONFIG.getPassengerWxAppKey();
        }
        if (payVo.getPaySide() == CommonConstant.PASSENGER_PULBIC) {
            appid = WXPAY_CONFIG.getPassengerPublicWxAppid();
            partner = WXPAY_CONFIG.getPassengerPublicWxPartner();
            key = WXPAY_CONFIG.getPassengerPublicWxAppKey();
        }
        if (payVo.getPaySide() == CommonConstant.PASSENGER_H5) {
            appid = WXPAY_CONFIG.getPassengerH5WxAppid();
            partner = WXPAY_CONFIG.getPassengerH5WxPartner();
            key = WXPAY_CONFIG.getPassengerH5WxAppKey();
        }
        if (payVo.getPaySide() == CommonConstant.PASSENGER_APPLET) {
            appid = WXPAY_CONFIG.getPassengerAppletWxAppid();
            partner = WXPAY_CONFIG.getPassengerAppletWxPartner();
            key = WXPAY_CONFIG.getPassengerAppletWxAppKey();
        }
        if (payVo.getPaySide() == CommonConstant.DRIVER) {
            appid = WXPAY_CONFIG.getDriverWxAppid();
            partner = WXPAY_CONFIG.getDriverWxPartner();
            key = WXPAY_CONFIG.getDriverWxAppKey();
        }
        if (StringUtils.isEmpty(appid) || StringUtils.isEmpty(partner)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到微信配置参数");
        }

        Map<String, String> map = new HashMap<String, String>();
        //订单的查询参数
        //公众账号ID
        map.put("appid", appid);
        //商户号
        map.put("mch_id", partner);
        //随机字符串
        map.put("nonce_str", Md5Utils.encode(String.valueOf(new Random().nextInt(10000))));
        //商户订单号
        map.put("out_trade_no", payVo.getTradeNo());
        //签名
        String sign = PaySignBuilder.wxSignMD5(map, key);
        if (StringUtils.isEmpty(sign)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "参数MD5签名失败");
        }
        map.put("sign", sign);
        String payXml = XmlUtils.buildXml(map);
        logger.info("微信支付请求参数：" + payXml);
        //微信需要http通讯请求预支付信息
        TenpayHttpClient httpClient = new TenpayHttpClient();
        String resultStr;
        Map<String, String> resultMap = new HashMap<String, String>();
        if (httpClient.callHttpPost("https://api.mch.weixin.qq.com/pay/orderquery", payXml)) {
            resultStr = httpClient.getResContent();
            resultMap = XmlUtils.readValueAsMap(resultStr);
        }

        if (resultMap == null || resultMap.isEmpty()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "微信XML解析异常");
        }

        logger.info("微信返回参数：" + resultMap);
        if (!"SUCCESS".equals(resultMap.get("return_code"))) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "微信通讯异常 -- " + resultMap.get("return_msg"));
        }

        if (!"SUCCESS".equals(resultMap.get("result_code"))) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "微信查询异常 -- " + resultMap.get("err_code_des"));
        }

        if ("SUCCESS".equals(resultMap.get("trade_state"))) {
            return ResponseData.buildSuccessResponse("微信支付成功", resultMap);
        }
        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "微信支付失败", resultMap);
    }

    //支付宝
    public static ResponseData<Map<String, String>> buildAliPayData(PayVo payVo) {
        String totalFeeCent = payVo.getActualFare().toString();
        //支付宝回调地址
        String aliCallBackUrl = SYS_CONFIG.getAlipayCallback();
        String url;
        if (ALIPAY_CONFIG.getAlipaySignTypeRsa2()) {
            Map<String, String> map = new HashedMap();
            //业务请求参数集合
            Map<String, Object> bizContent = MapUtils.build();
            //商户网站唯一订单号（流水号）
            bizContent.put("out_trade_no", payVo.getTradeNo());
            //商品名称
            bizContent.put("subject", payVo.getSubject());
            //总金额
            bizContent.put("total_fee", totalFeeCent);
            //销售产品码
            bizContent.put("product_code", "QUICK_MSECURITY_PAY");
            //商品详情
            bizContent.put("body", buildBody(payVo));
            //--以下为必填公共参数
            //APPID
//            map.put("app_id", ALIPAY_CONFIG.getOpenAppid());
            map.put("app_id", ALIPAY_CONFIG.getPayAppid());
            try {
                //业务请求参数集合
                map.put("biz_content", JsonUtils.writeJsonStr(bizContent));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            //参数编码字符集
            map.put("charset", "utf-8");
            //接口名称
            map.put("method", "alipay.trade.app.pay");
            //支付宝回调地址
            map.put("notify_url", aliCallBackUrl);
            map.put("sign_type", "RSA2");
            map.put("timestamp", DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            //接口版本
            map.put("version", "1.0");
            //构建签名串
            String signUrl = PayUrlBuilder.buildUrl(map, false, false, true);
            //签名
//            String sign = PaySignBuilder.signRSA(signUrl, ALIPAY_CONFIG.getOpenBizPrivateKey());
            String sign = PaySignBuilder.signRSA(signUrl, ALIPAY_CONFIG.getPayPrivateKey());
            if (StringUtils.isEmpty(sign)) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "参数签名失败");
            }
            //构建支付串
            url = PayUrlBuilder.buildUrl(map, false, true, false) + "&sign=" + sign;
        } else {
            String body = buildBody(payVo);
            Map<String, String> map = new HashMap<>(16);
            //--以下为必填参数
            //接口名称
            map.put("service", "mobile.securitypay.pay");
            //合作者身份ID
            map.put("partner", ALIPAY_CONFIG.getAliPartner());
            //参数编码字符集
            map.put("_input_charset", "utf-8");
            //支付宝回调地址
            map.put("notify_url", aliCallBackUrl);
            //商户网站唯一订单号（流水号）
            map.put("out_trade_no", payVo.getTradeNo());
            //商品名称
            map.put("subject", payVo.getSubject());
            //支付类型
            map.put("payment_type", "1");
            //卖家支付宝账号
            map.put("seller_id", ALIPAY_CONFIG.getAliSeller());
            //总金额
            map.put("total_fee", totalFeeCent);
            //商品详情
            map.put("body", body);
            //--以下为可选参数
            //未付款交易的超时时间
            map.put("it_b_pay", "30m");
            //商品主类型：0—虚拟类商品，1—实物类商品
            map.put("goods_type", "1");
            String enable_pay_str = "balance,moneyFund,coupon,pcredit,pcreditpayInstallment,creditCard,creditCardExpress,creditCardCartoon," +
                    "credit_group,debitCardExpress,mcard,pcard,promotion,voucher,point,mdiscount,bankPay";
            //可用渠道，用户只能在指定渠道范围内支付当有多个渠道时用“,”分隔
            map.put("enable_pay_channels", enable_pay_str);

            //签名
            url = PayUrlBuilder.buildUrl(map, true);
            String sign = PaySignBuilder.signRSA(url, ALIPAY_CONFIG.getRsaPrivateKey());
            if (StringUtils.isEmpty(sign)) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "参数RSA签名失败");
            }
            //RSA签名（必填）
            url += "&sign_type=\"RSA\"&sign=\"" + sign + "\"";
        }
        Map<String, String> map = new HashMap<>(2);
        map.put("url", url);
        return ResponseData.buildSuccessResponse("支付宝生成预支付信息成功", map);
    }

    //支付宝订单的查询
    public static ResponseData<String> selAliPayData(PayVo payVo) {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                ALIPAY_CONFIG.getOpenAppid(), ALIPAY_CONFIG.getOpenBizPrivateKey(), "json", "GBK",
                ALIPAY_CONFIG.getOpenBizPublicKey(), "RSA");
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent("{" +
                "\"out_trade_no\":\"" + payVo.getTradeNo() + "\"" +
                "}");
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            logger.info("支付宝通讯异常");
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "支付宝通讯异常");
        }

        if (!response.isSuccess()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "支付宝请求异常");
        }
        logger.info("支付宝返回参数：" + response.getBody());

        if ("10000".equals(response.getCode()) && " TRADE_SUCCESS".equals(response.getTradeStatus())) {
            return ResponseData.buildSuccessResponse("支付宝支付成功", response.getBody());
        }
        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "支付宝支付失败", response.getBody());
    }

    private static String buildBody(PayVo payVo) {
        return "【" + SYS_CONFIG.getName() + "】".trim() + "--" + payVo.getSubject() + "--" + payVo.getTradeNo();
    }

}
